package sfeir.ergosum.service;

import java.util.Date;
import java.util.Iterator;
import java.util.List;

import sfeir.ergosum.HiveActivity;
import sfeir.ergosum.R;
import sfeir.ergosum.dao.DatabaseConnection;
import sfeir.ergosum.dao.DatabaseProvider;
import sfeir.ergosum.dao.RemoteProvider;
import sfeir.ergosum.model.Address;
import sfeir.ergosum.model.Contact;
import sfeir.ergosum.model.Email;
import sfeir.ergosum.model.Person;
import sfeir.ergosum.model.Tel;
import sfeir.ergosum.tools.CachedImageView;
import android.app.AlarmManager;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Binder;
import android.os.ConditionVariable;
import android.os.IBinder;
import android.os.SystemClock;
import android.util.Log;
import android.widget.Toast;

/**
 */
public class ContactService extends Service {
    public static final String ACTION_CHECK_CONTACT = "sfeir.ergosum.intent.action.CONTACT_SERVICE_WAKEUP";
    private static final String ACTION_RESCHEDULE = "sfeir.ergosum.intent.action.CONTACT_SERVICE_RESCHEDULE";
    private static final String ACTION_CANCEL = "sfeir.ergosum.intent.action.CONTACTS_SERVICE_CANCEL";

    private NotificationManager mNM;

    // variable which controls the notification thread
    private ConditionVariable mCondition;

    private SharedPreferences mPrefs;

    public static void actionReschedule(Context context) {
        Intent i = new Intent();
        i.setClass(context, ContactService.class);
        i.setAction(ContactService.ACTION_RESCHEDULE);
        context.startService(i);
    }

    public static void actionUpdateContact(Context context) {
        Intent i = new Intent();

        i.setClassName("sfeir.ergosum", "sfeir.ergosum.service.ContactService");
        i.setAction(ContactService.ACTION_CHECK_CONTACT);
        context.startService(i);
    }

    public static void actionCancel(Context context) {
        Intent i = new Intent();
        i.setClassName("sfeir.ergosum", "sfeir.ergosum.service.ContactService");
        // i.setClass(context, ContactService.class);
        i.setAction(ContactService.ACTION_CANCEL);
        context.startService(i);
    }

    @Override
    public void onCreate() {
        Log.d("ErgoSum", "*** Create ErgoSum Contact service");
        super.onCreate();
    }

    @Override
    public void onStart(Intent intent, int startId) {
        super.onStart(intent, startId);
        Log.d("ErgoSum", "*** Start ErgoSum Contact service");
        mNM = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);

        if (ACTION_CHECK_CONTACT.equals(intent.getAction())) {
            Log.d("ErgoSum", "*** Updating contact");
            Thread notifyingThread = new Thread(null, mTaskUpdateContact,
                    "ContactService");
            mCondition = new ConditionVariable(false);
            notifyingThread.start();

        } else if (ACTION_CANCEL.equals(intent.getAction())) {
            Log.d("ErgoSum", "*** ErgosSum: cancel");
            cancel();
            stopSelf(startId);
        } else if (ACTION_RESCHEDULE.equals(intent.getAction())) {
            Log.d("ErgoSum", "*** ErgosSum: reschedule");
            reschedule();
            stopSelf(startId);
        }
    }

    private void showNotification(Contact contact) {
        // Set the icon, scrolling text and timestamp.
        // Note that in this example, we pass null for tickerText. We update the
        // icon enough that
        // it is distracting to show the ticker text every time it changes. We
        // strongly suggest
        // that you do this as well. (Think of of the "New hardware found" or
        // "Network connection
        // changed" messages that always pop up)
        String notifText = getString(R.string.service_updated_contact, contact
                .getAlias());

        Notification notification = new Notification(R.drawable.icon,
                notifText, System.currentTimeMillis());

        Intent intent = new Intent(this, HiveActivity.class);
        intent.putExtra("contact", contact);
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
        // The PendingIntent to launch our activity if the user selects this
        // notification
        PendingIntent contentIntent = PendingIntent.getActivity(this, 0,
                intent, 0);

        // Set the info for the views that show in the notification panel.
        notification.setLatestEventInfo(this, notifText, notifText,
                contentIntent);

        // Send the notification.
        // We use a layout id because it is a unique number. We use it later to
        // cancel.
        mNM.notify((int) contact.getId(), notification);
    }

    private Runnable mTaskUpdateContact = new Runnable() {
        public void run() {
            DatabaseProvider dp = new DatabaseProvider(new DatabaseConnection(
                    getApplicationContext()));
            dp.open();
            List<Contact> list = dp.getAllContacts();
            dp.close();
            mPrefs = getSharedPreferences(getPackageName() + "_preferences",
                    MODE_WORLD_READABLE);
            // .getDefaultSharedPreferences();
            String updateDays = mPrefs.getString("preference_frequence_maj",
                    "0");
            Boolean pref_not_email = mPrefs.getBoolean(
                    "preference_notification_email", false);
            Boolean pref_not_tel = mPrefs.getBoolean(
                    "preference_notification_tel", false);
            Boolean pref_not_pict = mPrefs.getBoolean(
                    "preference_notification_picture", false);
            Boolean pref_not_adress = mPrefs.getBoolean(
                    "preference_notification_adress", false);
            Integer days = Integer.parseInt(updateDays);
            if (days != 0) {
                Long updateTime = new Date().getTime()
                        - (days * 24 * 60 * 60 * 1000);
                if (!mCondition.block(1 * 1000)) {
                    for (Contact contact : list) {
                        if (contact.getUpdated() < updateTime) {
                            Log.d("ErgoSum", "Update contact "
                                    + contact.getAlias());
                            String url = contact.getUrl();
                            if (null == url)
                                continue;
                            Person newPerson = RemoteProvider.getUpdatedPerson(
                                    url, ContactService.this
                                            .getContentResolver());
                            Person person = contact.getPerson();

                            if (newPerson != null && person != null) {

                                Boolean notify = false;
                                if (pref_not_email
                                        && testIsNewMail(person, newPerson)) {
                                    notify = true;
                                }
                                if (pref_not_tel
                                        && testIsNewTel(person, newPerson)) {
                                    notify = true;
                                }
                                if (pref_not_pict
                                        && testIsNewPicture(person, newPerson)) {
                                    notify = true;
                                }
                                if (pref_not_adress
                                        && testIsNewAdress(person, newPerson)) {
                                    notify = true;
                                }
                                newPerson.setId(person.getId());
                                contact.setPerson(newPerson);
                                if (notify)
                                    showNotification(contact);
                                dp.open();
                                String oldImageUrl = person.getPhoto();
                                if (oldImageUrl != null) {
                                    ContactService.this.deleteFile(CachedImageView
                                        .md5(oldImageUrl));
                                }
                                dp.updateFullContactWithTimestamp(contact);
                                dp.close();
                            }
                            if (mCondition.block(1 * 1000))
                                break;
                        }
                    }
                    Log.d("ErgoSum", "*** End update contacts");

                }
            }
            // Done with our work... stop the service!
            ContactService.this.stopSelf();
        }

        private Boolean testIsNewMail(Person person, Person newPerson) {
            List<Email> newlistemail = newPerson.getEmails();
            List<Email> listemail = person.getEmails();
            Boolean isNewEmail = false;
            if (newlistemail != null && listemail != null) {
                for (Email newEmail : newlistemail) {
                    Boolean find = false;
                    String newmail = newEmail.getEmail();
                    if (newmail != null) {
                        for (Iterator<Email> it = listemail.iterator(); !find
                                && it.hasNext();) {
                            Email email = it.next();
                            if (!newmail.equals(email.getEmail()))
                                continue;
                            find = true;
                        }
                        if (!find) {
                            isNewEmail = true;
                        }
                    }
                }
            }
            return isNewEmail;
        }

        private Boolean testIsNewTel(Person person, Person newPerson) {
            List<Tel> newlistTel = newPerson.getTels();
            List<Tel> listeTel = person.getTels();
            Boolean isNewTel = false;
            if (newlistTel != null && listeTel != null) {
                for (Tel newTel : newlistTel) {
                    Boolean find = false;
                    String newtel = newTel.getPhoneNumber();
                    if (newtel != null) {
                        for (Iterator<Tel> it = listeTel.iterator(); !find
                                && it.hasNext();) {
                            Tel tel = it.next();
                            if (!newtel.equals(tel.getPhoneNumber()))
                                continue;
                            find = true;
                        }
                        if (!find) {
                            isNewTel = true;
                        }
                    }
                }
            }
            return isNewTel;
        }

        private Boolean testIsNewAdress(Person person, Person newPerson) {
            List<Address> newlistadress = newPerson.getAddresses();
            List<Address> listAdress = person.getAddresses();
            Boolean isNewAdress = false;
            if (newlistadress != null && listAdress != null) {
                for (Address newAdress : newlistadress) {
                    Boolean find = false;
                    String newadress = newAdress.getFullValue();
                    if (newadress != null) {
                        for (Iterator<Address> it = listAdress.iterator(); !find
                                && it.hasNext();) {
                            Address adress = it.next();
                            if (!newadress.equals(adress.getFullValue()))
                                continue;
                            find = true;
                        }
                        if (!find) {
                            isNewAdress = true;
                        }
                    }
                }
            }
            return isNewAdress;
        }

        private Boolean testIsNewPicture(Person person, Person newPerson) {
            if (person.getPhoto() != null && !person.getPhoto().equals(newPerson.getPhoto())) {
                return true;
            } else
                return false;
        }
    };

    @Override
    public void onDestroy() {
        super.onDestroy();
        // mNM.cancel(MOOD_NOTIFICATIONS);
        // Stop the thread from generating further notifications
        mCondition.open();
        Toast.makeText(ContactService.this, R.string.update_stop, 500).show();
    }

    private void cancel() {
        AlarmManager alarmMgr = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
        Intent i = new Intent();
        i.setClassName("sfeir.ergosum", "sfeir.ergosum.service.ContactService");
        i.setAction(ACTION_CHECK_CONTACT);
        PendingIntent pi = PendingIntent.getService(this, 0, i, 0);
        alarmMgr.cancel(pi);
    }

    private void reschedule() {
        AlarmManager alarmMgr = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
        Intent i = new Intent();
        i.setClassName("sfeir.ergosum", "sfeir.ergosum.service.ContactService");
        i.setAction(ACTION_CHECK_CONTACT);
        PendingIntent pi = PendingIntent.getService(this, 0, i, 0);
        mPrefs = getSharedPreferences(getPackageName() + "_preferences",
                MODE_WORLD_READABLE);
        // .getDefaultSharedPreferences();
        String updateDays = mPrefs.getString("preference_frequence_maj", "0");
        Integer days = Integer.parseInt(updateDays);
        if (days == 0) {
            alarmMgr.cancel(pi);
        } else {
            alarmMgr.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock
                    .elapsedRealtime()
                    + (days * (60 * 1000)), pi);
        }
    }

    @Override
    public IBinder onBind(Intent intent) {
        return binder;
    }

    private final IBinder binder = new MyBinder();

    public class MyBinder extends Binder {
        ContactService getService() {
            return ContactService.this;
        }
    }
}
